package com.example.blog.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.blog.config.PublisherAware;
import com.example.blog.domain.*;
import com.example.blog.dto.operationalLogs.OperationLogsDto;
import com.example.blog.dto.publicDto.AdminUpdateDto;
import com.example.blog.dto.publicDto.CancelAccountDto;
import com.example.blog.dto.publicDto.PageDto;
import com.example.blog.dto.publicDto.PasswordModificationDto;
import com.example.blog.dto.userInfo.AdminSelectUserInfoDto;
import com.example.blog.dto.userInfo.AdminUpdateUserInfoDto;
import com.example.blog.dto.userInfo.UserInfoUpdateDto;
import com.example.blog.dto.users.AdminSelectAdminInfoDto;
import com.example.blog.dto.users.UserDto;
import com.example.blog.event.publisher.LoggingApplicationEvent;
import com.example.blog.mapper.UserInformationMapper;
import com.example.blog.note.LogInfo;
import com.example.blog.note.NoToken;
import com.example.blog.note.Permissions;
import com.example.blog.service.impl.*;
import com.example.blog.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.mail.MessagingException;
import javax.validation.constraints.Min;
import java.text.SimpleDateFormat;
import java.util.*;


@RestController
@Transactional
@Validated
@RequestMapping("/userInformation")
public class UserInfoController extends BaseController {
    private final UserInformationServiceImpl userInformation;
    private final MyMail myMail;
    private final UserInformationMapper userInformationMapper;
    private final RedisStorage redisStorage;
    private final UserServiceImpl userService;
    private final UserRoleServiceImpl userRoleService;
    private final OperationalLogsServiceImpl logsService;
    private final PublisherAware loggingPublisherAware;

    @Autowired
    public UserInfoController(
                              OperationalLogsServiceImpl logsService,
                              UserRoleServiceImpl userRoleService,
                              UserServiceImpl userService,
                              RedisStorage redisStorage,
                              UserInformationMapper userInformationMapper,
                              MyMail myMail,
                              UserInformationServiceImpl userInformation,
                              PublisherAware loggingPublisherAware) {
        this.userService = userService;
        this.logsService = logsService;
        this.userRoleService = userRoleService;
        this.redisStorage = redisStorage;
        this.userInformationMapper = userInformationMapper;
        this.myMail = myMail;
        this.userInformation = userInformation;
        this.loggingPublisherAware = loggingPublisherAware;
    }

    //通过用户id查询用户的信息
    @NoToken
    @LogInfo("查询单个用户的信息")
    @GetMapping("/save/{uid}")
    public Response saveUser(@PathVariable("uid") long id) {
        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInformation::getUid, id);
        UserInformation info = userInformation.getOne(wrapper);
        info.setPhone("");
        return new Response(Response.SUCCEED_CODE, "查询成功", info);
    }

    //通过用户id查询单个用户的头像和用户名
    @NoToken
    @LogInfo("查询用户的头像和用户名")
    @GetMapping("/save/senderInfo/{uid}")
    public Response saveSenderInfo(@PathVariable("uid") long id) {
        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInformation::getUid, id).select(UserInformation::getUsername, UserInformation::getAvatar);
        return new Response(Response.SUCCEED_CODE, "查询成功", userInformation.getOne(wrapper));
    }

    //通过用户id查询单个用户文章详情个人展示信息
    @NoToken
    @LogInfo("用户文章详情个人展示信息")
    @GetMapping("/save/essayInfo/{uid}")
    public Response saveEssayUserInfo(@PathVariable("uid") long id) {
        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInformation::getUid, id).select(UserInformation::getUsername, UserInformation::getAvatar, UserInformation::getMotto);
        return new Response(Response.SUCCEED_CODE, "查询成功", userInformation.getOne(wrapper));
    }

    //更新用户的信息
    @LogInfo("更新用户信息")
    @PostMapping("/updateUserInfo")
    public Response updateUser(@RequestBody UserInfoUpdateDto userVo) {
        UserInformation user = new UserInformation();
        BeanUtils.copyProperties(userVo, user);
        return new Response(Response.SUCCEED_CODE, "更新成功", userInformation.update(user, new QueryWrapper<UserInformation>().eq("uid", getLogSign().getUid())));
    }

    //    //通过用户名(不是账号)查询单个用户信息
//    @NoToken
//    @LogInfo("通过用户名(不是账号)查询单个用户信息")
//    @GetMapping("/{msg}")
//    public Response saveOne(@PathVariable String msg) {
//        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
//        wrapper.like(UserInformation::getUsername, msg);
//        return new Response(Response.SUCCEED_CODE, "查询成功", userInformation.getOne(wrapper));
//    }
    //通过用户ID查询单个用户信息
    @NoToken
    @LogInfo("通过用户名(ID)查询单个用户信息")
    @GetMapping("getByID/{id}")
    public Response getByID(@PathVariable("id") Long id) {
        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInformation::getUid, id);
        return new Response(Response.SUCCEED_CODE, "查询成功", userInformation.getOne(wrapper));
    }

    //上传用户头像
    @LogInfo("上传用户头像")
    @PostMapping("/uploadImage/heard")
    public Response uploadImageHeard(MultipartFile[] file, String oldImg) {
        String path = userInformation.uploadUserHeadImg(file, oldImg);
        if (path == null) {
            return new Response(Response.ERROR_CODE, "格式错误或文件上传过多", null);
        }
        UpdateWrapper<UserInformation> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("uid", getLogSign().getUid()).set("avatar", path);
        userInformation.update(updateWrapper);
        return new Response(Response.SUCCEED_CODE, "上传成功", path);
    }



    //上传用户头像
    @LogInfo("上传测试图盘")
    @NoToken
    @PostMapping("/uploadImage")
    public Response uploadImageHeard99(MultipartFile file) {
        String oldImg = "http://www.lyzhnb.top/30e89d0a-9ddb-48c4-9935-cb25638bb701123";
        String path = userInformation.uploadUserHeadImg(new MultipartFile[]{file}, oldImg);
        if (path == null) {
            return new Response(Response.ERROR_CODE, "格式错误或文件上传过多", null);
        }
        return new Response(Response.SUCCEED_CODE, "上传图盘", path);
    }



    //用户注册
    @NoToken
    @LogInfo("新用户注册")
    @PostMapping("/enroll")
    public Response enroll(@RequestBody Users users) {
        String msg = "error";
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (redisStorage.checkEnrollCaptcha(users.getEmail(), users.getCaptcha())) {
            users.setAccount(users.getUsername());
            users.setPassword(bCryptPasswordEncoder.encode(users.getPassword()));
            userService.save(users);
            if (userInformation.insertUserInfo(users)) {
                msg = "success";
            }
        }
        return new Response(Response.SUCCEED_CODE, "注册成功", msg);
    }

    //发送注册邮箱验证码
    @NoToken
    @LogInfo("发送注册邮箱验证码")
    @PostMapping("/enroll/captcha")
    public Response captcha(@RequestBody String email) throws MessagingException {
        String captcha = myMail.myMailCaptcha();
        String em = email.substring(1, email.length() - 1);
        myMail.sendSimpleMail(
                "验证码", em,
                "<h3> 验证码 ·</h3>" +
                        "<p>" + "该验证码用于注册或登录账户,如不是您本人操作,请引起注意" + "</p>" +
                        "<p>" + captcha + "</p>"
                , true);
        redisStorage.insertCaptcha(em, captcha, 60);
        return new Response(Response.SUCCEED_CODE, "发送成功", null);
    }

    //找回密码
    @NoToken
    @LogInfo("用户找回密码")
    @PostMapping("/recover/pas")
    public Response recoverThePassword(@RequestBody PasswordModificationDto users) {
        UpdateWrapper<Users> wrapper = new UpdateWrapper<>();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean result = false;
        if (redisStorage.checkEnrollCaptcha(users.getEmail(), users.getCaptcha())) {
            wrapper.eq("email", users.getEmail())
                    .set("password", bCryptPasswordEncoder.encode(users.getPassword()));
            result = userService.update(null, wrapper);
        }
        return new Response(Response.SUCCEED_CODE, result ? "找回成功" : "找回失败", result);

    }

    //注销账号
    @PostMapping("/deleteAuto")
    @LogInfo(value = "注销账号")
    public Response deleteAuto(@RequestBody CancelAccountDto cancelAccountVo) {
        if (!redisStorage.checkEnrollCaptcha(cancelAccountVo.getCaptchaId(), cancelAccountVo.getCaptcha())) {
            return new Response(Response.ERROR_CODE, "验证码错误或失效", 0);
        }
        UpdateWrapper<UserInformation> wrapper = new UpdateWrapper<>();
        wrapper.eq("uid", getLogSign().getUid()).set("state", -1);
        userInformation.update(null, wrapper);
        return new Response(Response.SUCCEED_CODE, "注销成功", 1);
    }

    //Admin查询全部用户信息(按条件)
    @LogInfo("Admin查询全部用户信息")
    @PostMapping("/admin/getUserAll/condition")
    public Response getUserAllAdmin(@RequestBody AdminSelectUserInfoDto userInfoPage) {
        IPage page = new Page(userInfoPage.getIndex(), userInfoPage.getPage());
        LambdaQueryWrapper<UserInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .orderByDesc(userInfoPage.getSortBy() == 1, UserInformation::getIntegral)
                .orderByAsc(userInfoPage.getSortBy() == 0, UserInformation::getIntegral)
                .eq(userInfoPage.getTypes() != 2, UserInformation::getState, userInfoPage.getTypes())
                .like(Objects.nonNull(userInfoPage.getDateTime()), UserInformation::getRegistrationTime, userInfoPage.getDateTime());
        Optional.ofNullable(userInfoPage.getCondition())
                .ifPresent(s -> {
                    queryWrapper.and(wrapper ->
                                    wrapper.like(UserInformation::getEmail, userInfoPage.getCondition()))
                            .or()
                            .like(UserInformation::getUsername, userInfoPage.getCondition())
                            .or()
                            .like(UserInformation::getAccount, userInfoPage.getCondition())
                            .or()
                            .eq(UserInformation::getUid, userInfoPage.getCondition());
                });
        return new Response(Response.SUCCEED_CODE, "查询成功", userInformation.page(page, queryWrapper));
    }

    //Admin更新用户信息
    @Permissions("/userInformation/updateAdmin")
    @LogInfo("Admin更新用户信息")
    @PostMapping("/updateAdmin")
    public Response updateAdmin(@RequestBody AdminUpdateUserInfoDto userInformation_) {
        OperationLogsDto logsVo = new OperationLogsDto(
                0, IpUtil.getIpAddress(getHttpInfo()), "Admin更新用户信息", getLogSign(), null);
        UserInformation userInfo = new UserInformation();
        BeanUtils.copyProperties(userInformation_, userInfo);
        return new Response(Response.SUCCEED_CODE, "更新成功", userInformation.updateAdminUserInfo(userInfo, logsVo));
    }


    //搜索(后台管理)
    @Permissions("/userInformation/searchAdmin")
    @LogInfo("搜索(后台管理)")
    @GetMapping("/searchAdmin/{msg}")
    public Response selectAdminSearch(@PathVariable("msg") String msg) {
        LambdaQueryWrapper<UserInformation> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(UserInformation::getUid, msg)
                .or()
                .like(UserInformation::getUsername, msg)
                .or()
                .like(UserInformation::getAccount, msg)
                .or()
                .like(UserInformation::getEmail, msg)
                .or()
                .like(UserInformation::getPhone, msg)
                .orderByDesc(UserInformation::getRegistrationTime);
        return new Response(Response.SUCCEED_CODE, "搜索成功", userInformation.list(wrapper));
    }

    //获取所有管理员信息
    @Permissions("/userInformation/getAll/admin")
    @LogInfo("获取所有管理员信息(后台管理)")
    @PostMapping("/getAll/admin")
    public Response getAllAdmin(@RequestBody AdminSelectAdminInfoDto adminInfoDto) {
        Map<String, Object> userInformation_ = new HashMap<>();
        userInformation_.put("content", userInformationMapper.AdminInfo(adminInfoDto.getIndex() - 1, adminInfoDto.getPage()));
        userInformation_.put("statistics", userInformationMapper.statisticsAdminInfo());

        return new Response(Response.SUCCEED_CODE, "获取成功", userInformation_);
    }


    //新增管理员
    @Permissions("/supperAdmin")
    @LogInfo("新增管理员")
    @PostMapping("/supperAdmin/insert")
    public Response insert(MultipartFile file, String username, String password) {
        OperationLogsDto logsVo = new OperationLogsDto(
                1, IpUtil.getIpAddress(getHttpInfo()), "新增管理员", getLogSign(), null);
        return new Response(Response.SUCCEED_CODE, "新增成功", userInformation.addAdmin(file, username, password, logsVo));
    }

    //修改管理员权限
    @Permissions("/supperAdmin")
    @LogInfo("修改管理员权限")
//    @PutMapping("/supperAdmin/update")
    public Response update(@RequestBody UserDto userRoleVo) {
        UpdateWrapper<UserRole> wrapper = new UpdateWrapper<>();
        wrapper.set("rid", userRoleVo.getRid()).eq("uid", userRoleVo.getUid());
        OperationalLogs operationalLogs = new OperationalLogs(0, 1, getLogSign().getUsername(), userRoleVo.getUsername(), "修改管理员权限");
        operationalLogs.setUser("修改管理员权限：" + userRoleVo.getUid());
        try {
            userRoleService.update(null, wrapper);
            logsService.save(operationalLogs);
            return new Response(Response.SUCCEED_CODE, "修改成功", 1);
        } catch (Exception e) {
            operationalLogs.setOutcome(0);
            logsService.save(operationalLogs);
            return new Response(Response.ERROR_CODE, "修改失败", 0);
        }
    }

    //Admin删除管理员
    @Permissions("/supperAdmin")
    @LogInfo("删除管理员")
    @DeleteMapping("/supperAdmin/delete/{id}")
    public Response delete(@PathVariable("id") long id) {
        OperationLogsDto logsVo = new OperationLogsDto(
                -1, IpUtil.getIpAddress(getHttpInfo()), "删除管理员", getLogSign(), "管理员id：".concat(String.valueOf(id)));
        boolean remove = false;
        return new Response(Response.SUCCEED_CODE, "删除成功", userInformation.delAdminUser(id, logsVo));
    }

    //Admin删除用户信息
    @Permissions("/userInformation/deleteAdmin")
    @LogInfo("Admin删除用户信息")
    @DeleteMapping("/deleteAdmin/{id}")
    public Response deleteAdmin(@Min(value = 1, message = "最小值为1") @PathVariable("id") Long id) {
        OperationLogsDto logsVo = new OperationLogsDto(
                -1, IpUtil.getIpAddress(getHttpInfo()), "Admin删除用户信息", getLogSign(), "用户id：".concat(String.valueOf(id)));
        return new Response(Response.SUCCEED_CODE, "删除成功", userInformation.delAdminUser(id, logsVo));
    }


    //Admin获取所有用户总数
    @Permissions("/userInformation/getAll/length")
    @LogInfo("获取所有用户总数(后台管理)")
    @GetMapping("/getAll/length")
    public Response getUserLength() {
        return new Response(Response.SUCCEED_CODE, "获取成功", userInformationMapper.userLength());
    }

    //Admin获取当日登录用户总数
    @Permissions("/userInformation/userLogin/day")
    @LogInfo("获取当日登录用户总数(后台管理)")
    @GetMapping("/userLogin/day")
    public Response userLoginDay() {
        return new Response(Response.SUCCEED_CODE, "获取成功", userInformationMapper.loginDay());
    }


    //更改Admin基本信息
    @Permissions("/userInformation/AdminInfo")
    @LogInfo("更改Admin基本信息")
    @PostMapping("/AdminInfo")
    public Response AdminInfo(@RequestBody AdminUpdateDto adminUpdateVo) {
        System.out.println(adminUpdateVo);
        OperationLogsDto logsVo = new OperationLogsDto(
                0, IpUtil.getIpAddress(getHttpInfo()), "更改Admin基本信息", getLogSign(), getLogSign().getUsername());
        boolean result = false;
        try {
            UpdateWrapper<UserInformation> wrapper = new UpdateWrapper<>();

            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            Optional.ofNullable(adminUpdateVo.getPassword())
                    .ifPresent(s -> {
                        UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.eq("uid", getLogSign().getUid())
                                .set("password", bCryptPasswordEncoder.encode(adminUpdateVo.getPassword()));
                        userService.update(null, updateWrapper);
                    });
            Optional.ofNullable(adminUpdateVo.getUsername())
                    .ifPresent(s -> {
                        UpdateWrapper<Users> updateWrapper_ = new UpdateWrapper<>();
                        updateWrapper_.eq("uid", getLogSign().getUid())
                                .set("account", adminUpdateVo.getUsername());
                        userService.update(null, updateWrapper_);
                        wrapper.eq("uid", getLogSign().getUid())
                                .set("username", adminUpdateVo.getUsername());
                        userInformation.update(null, wrapper);
                    });
            logsVo.setOutcome(0);
            loggingPublisherAware.publisher(new LoggingApplicationEvent(logsVo));
        } catch (Exception e) {
            logsVo.setOutcome(1);
            loggingPublisherAware.publisher(new LoggingApplicationEvent(logsVo));
            throw e;
        }
        return new Response(Response.SUCCEED_CODE, "更改成功", result);
    }
}
